#include <func.h>
typedef struct connInfo_s {
    int isAlive;
    int netfd;
    time_t lastActive;
} connInfo_t;
int main(int argc, char *argv[])
{
    // ./1_chatroom_select 192.168.38.128 1234
    ARGS_CHECK(argc,3);
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in addr;
    addr.sin_family = AF_INET; // AF_INET ipv4
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    int flag = 1; // 给SO_REUSEADDR属性的参数分配内存
    int ret = setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
    // 赋值用具体类型 传参时强转成公共类型
    ret = bind(sockfd,(struct sockaddr *)&addr, sizeof(addr));
    // 服务端 bind 只能绑定服务端地址
    ERROR_CHECK(ret,-1,"bind");
    listen(sockfd,10);
    
    fd_set readyset;
    fd_set monitorset;
    FD_ZERO(&monitorset);
    FD_SET(sockfd,&monitorset);

    char buf[4096];
    connInfo_t connInfo[1024];// connInfo存储了接入客户端的信息
    for(int i = 0; i < 1024; ++i){
        connInfo[i].isAlive = 0;
    }
    int curidx = 0; // 下一个要加入的netfd的下标
    while(1){
        memcpy(&readyset,&monitorset,sizeof(fd_set));
        struct timeval timeout;
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;
        select(1024,&readyset,NULL,NULL,&timeout);
        time_t curtime = time(NULL);
        printf("curtime = %s\n", ctime(&curtime));
        if(FD_ISSET(sockfd,&readyset)){
            // accept
            connInfo[curidx].isAlive = 1;
            connInfo[curidx].netfd = accept(sockfd,NULL,NULL);
            printf("curidx = %d, netfd = %d\n", curidx, connInfo[curidx].netfd);
            FD_SET(connInfo[curidx].netfd,&monitorset);
            connInfo[curidx].lastActive = time(NULL);
            ++curidx;
        }
        for(int i = 0; i < curidx; ++i){
            if(connInfo[i].isAlive != 0 && FD_ISSET(connInfo[i].netfd,&readyset)){
                printf("ready, netfd = %d\n", connInfo[i].netfd);
                bzero(buf,sizeof(buf));
                ssize_t sret = recv(connInfo[i].netfd,buf,sizeof(buf),0);
                if(sret == 0){
                    // 有某个客户端断开连接了
                    printf("idx = %d, connInfo = %d\n",i, connInfo[i].netfd);
                    close(connInfo[i].netfd);
                    FD_CLR(connInfo[i].netfd,&monitorset);
                    connInfo[i].isAlive = 0;
                    continue;
                }
                connInfo[i].lastActive = time(NULL);
                for(int j = 0; j < curidx; ++j){
                    if(j == i || connInfo[j].isAlive == 0){
                        continue;
                    }
                    send(connInfo[j].netfd,buf,strlen(buf),0);
                }
            }
        }
        for(int i = 0; i < curidx; ++i){
            if(connInfo[i].isAlive != 0 && curtime - connInfo[i].lastActive >= 10){
                printf("timeout , idx = %d, connInfo = %d\n", i, connInfo[i].netfd);
                close(connInfo[i].netfd);
                FD_CLR(connInfo[i].netfd,&monitorset);
                connInfo[i].isAlive = 0;
            }
        }
    }
    return 0;
}

